/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/

#include <string.h>
#include <math.h>
#include <time.h>
#include <sys/timeb.h>
#include <stdlib.h>

#if defined(WIN32) && !defined(__MINGW32__)
#include <conio.h>
#include <IO.H>
#endif
#include <assert.h>

#include "contributors.h"
#include "global.h"
#include "configfile.h"
#include "memalloc.h"
#include "header.h"
#include "ratectl.h"
#include "vlc.h"
#include "bbv.h"
#include "adaptiverounding.h"
#include "macroblock.h"

#ifdef FastME
#include "fast_me.h"
#endif

input_t inputs, *input = &inputs;
image_t images, *img   = &images;
snr_t snrs, *snr       = &snrs;
stat_t stats, *stat    = &stats;
bbv_buffer_t *p_bbv    = NULL;

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void init_mv_range()
{
    if ( input->profile_id == 0x20 )
    {
        switch ( input->level_id )
        {
            case 0x10:
                min_v_mv = -512;
                max_v_mv = 511;
                min_h_mv = -8192;
                max_h_mv = 8191;
                break;
            case 0x20:
                if ( 1 /*img->picture_structure*/ )
                {
                    min_v_mv = -1024;
                    max_v_mv = 1023;
                }
                else
                {
                    min_v_mv = -512;
                    max_v_mv = 511;
                }
                min_h_mv = -8192;
                max_h_mv = 8191;
                break;
            case 0x22:
                if ( 1 /*img->picture_structure*/ )
                {
                    min_v_mv = -1024;
                    max_v_mv = 1023;
                }
                else
                {
                    min_v_mv = -512;
                    max_v_mv = 511;
                }
                min_h_mv = -8192;
                max_h_mv = 8191;
                break;
            case 0x40:
                if ( 1 /*img->picture_structure*/ )
                {
                    min_v_mv = -2048;
                    max_v_mv = 2047;
                }
                else
                {
                    min_v_mv = -1024;
                    max_v_mv = 1023;
                }
                min_h_mv = -8192;
                max_h_mv = 8191;
                break;
            case 0x42:
                if ( 1 /*img->picture_structure*/ )
                {
                    min_v_mv = -2048;
                    max_v_mv = 2047;
                }
                else
                {
                    min_v_mv = -1024;
                    max_v_mv = 1023;
                }
                min_h_mv = -8192;
                max_h_mv = 8191;
                break;
        }
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void init_infor()
{
    printf( "-----------------------------------------------------------------------------\n" );
    printf( " Input YUV file                    : %s \n", input->in_file );
    printf( " Output  bitstream              : %s \n", input->out_file );
    if ( p_rec != -1 )
        printf( " Output log file                    : log.dat \n" );
    printf( " Output statistics file             : stat.dat \n" );
    printf( "-----------------------------------------------------------------------------\n" );
    printf( " Frame   Bit/pic   QP   SnrY    SnrU    SnrV    Time(ms)  FRM/FLD  IntraMBs\n" );
}

static bitstream_t* alloc_bitstream()
{
    const int buffer_size = ( img->width * img->height * 4 );
    bitstream_t *targe_stream;
    if ( ( targe_stream = ( bitstream_t * ) calloc( 1, sizeof( bitstream_t ) ) ) == NULL )
        no_mem_exit( "malloc_slice: bitstream_t" );
    if ( ( targe_stream->stream_buffer = ( byte * ) calloc( buffer_size, sizeof( byte ) ) ) == NULL )
        no_mem_exit( "malloc_slice: StreamBuffer" );

    targe_stream->bits_to_go = 8;
    return targe_stream;
}


/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static int init_glb_buf()
{
    int memory_size = 0;
    int refnum, i, row_idx;
    memory_size += get_mem2D_byte( &intra_pred, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    memory_size += get_mem2D_byte( &inter_pred, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    memory_size += get_mem2D_int( &diffy,       MB_BLOCK_SIZE, MB_BLOCK_SIZE );

    imgY_org_buffer = ( byte* )malloc( input->img_height*input->img_width*3/2 );
    memory_size += input->img_height*input->img_width*3/2;

    memory_size += get_mem2D_byte ( &img_y_org        , img->height        , img->width );
    memory_size += get_mem3D_byte ( &img_uv_org       , UV                 , img->height_cr , img->width_cr );
    for ( refnum=0; refnum<MAX_REF_NUM_PLUS_1; refnum++ )
    {
        memory_size += get_mem2D_mv( &frm_mv[refnum], img->b8_height , img->b8_width );
        memory_size += get_mem4D_mv( &frm_mv_4x4[refnum], ( img->height )/8 , ( img->width )/8, 2 , 2 );
    }

    for ( row_idx=0; row_idx<MB_BLOCK_SIZE; row_idx++ )
    {
        for ( i=0; i<MB_BLOCK_SIZE; i++ )
        {
            intra_pred[row_idx][i] = 128;
        }
    }
    for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
    {
        memory_size += get_mem2D_byte ( &img_y_rec_space[refnum] , img->p_height , img->p_width );
    }

    for ( i = 0; i < UV; i++ )
    {
        for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
        {
            memory_size += get_mem2D_byte ( &img_uv_rec_space[i][refnum] , img->p_height_cr , img->p_width_cr );
        }
    }
    //reference frame buffer
    for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
    {
#if QUARTER_PIXEL
        for ( i = 0; i < HALF_POS_NUM + QUATER_POS_NUM; i++ )
#else
        for ( i = 0; i < HALF_POS_NUM; i++ )
#endif
        {
            memory_size += get_mem2D_byte( &y_up_sampling[refnum][i], img->p_height, img->p_width );
        }
    }

    /*if (input->succe_b != 0)*/
    {
        memory_size += get_mem2D_bi_mv( &frm_bi_mv, img->b8_height , img->b8_width );
        memory_size += get_mem4D_bi_mv( &frm_bi_mv_4x4, ( img->height )/8 , ( img->width )/8, 2 , 2 );
#ifdef FastME
        if ( input->UseFME == 1 )
        {
            memory_size += get_mem4D_mv( &last_frm_mv_4x4, ( img->height )/8 , ( img->width )/8, 2 , 2 );
            memory_size += get_mem4D_bi_mv( &last_frm_bi_mv_4x4, ( img->height )/8 , ( img->width )/8, 2 , 2 );

            memory_size += get_mem4D_mv( &curr_frm_mv_4x4, ( img->height )/8 , ( img->width )/8, 2 , 2 );

            memory_size += get_mem4D_bi_mv( &curr_frm_bi_mv_4x4, ( img->height )/8 , ( img->width )/8, 2 , 2 );
        }
#endif
    }

    memory_size += get_mem2D_byte( &nextP_imgY, img->height, img->width );
    memory_size += get_mem3D_byte( &nextP_imgUV, 2, img->height_cr, img->width_cr );

#if DEBLOCK
    memory_size += get_mem2D_byte( &p_img_y_rec_deblock, img->height, img->width );
    memory_size += get_mem3D_byte( &p_img_uv_rec_deblock, 2, img->height_cr, img->width_cr );
    memory_size += get_mem2D_byte( &nextP_imgY_deblock, img->height, img->width );
    memory_size += get_mem3D_byte( &nextP_imgUV_deblock, 2, img->height_cr, img->width_cr );
#endif

    allalpha_lum = ( int * )malloc( img->total_mb_num * sizeof( int ) );
    allbelta_lum = ( int * )malloc( img->total_mb_num * sizeof( int ) );

    for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
    {
        img_y_rec_space_offset[refnum] = ( byte** )calloc( img->height, sizeof( byte* ) );
    }
    for ( i = 0; i < UV; i++ )
    {
        for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
        {
            img_uv_rec_space_offset[i][refnum] = ( byte** )calloc( img->height_cr, sizeof( byte* ) );
        }
    }

    for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
    {
        for ( row_idx = 0; row_idx < img->height; row_idx++ )
        {
            img_y_rec_space_offset[refnum][row_idx]  = ( byte* )( img_y_rec_space[refnum][IMG_PAD_SIZE+row_idx] + IMG_PAD_SIZE );
        }
        for ( i = 0; i < UV; i++ )
        {
            for ( row_idx = 0; row_idx < img->height_cr; row_idx++ )
            {
                img_uv_rec_space_offset[i][refnum][row_idx] = ( byte* )( img_uv_rec_space[i][refnum][IMG_PAD_SIZE/2+row_idx] + IMG_PAD_SIZE/2 );
            }
        }
    }

    p_img_y_rec     = img_y_rec_space_offset[2];
    p_img_uv_rec[0] = img_uv_rec_space_offset[0][2];
    p_img_uv_rec[1] = img_uv_rec_space_offset[1][2];
    return ( memory_size );
}

static void init_qcoder()
{
    qcoder = ( qcoder_env_t* )calloc( 1, sizeof( qcoder_env_t ) );
    return;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void init_img()
{
    int i;
    static const float frame_rate[8] = { 24000 / 1001, 24, 25, 30000 / 1001, 30, 50, 60000 / 1001, 60 };

    img->buf_cycle         = 1;
    img->width             = input->img_width  + img->auto_crop_right;
    img->height            = input->img_height + img->auto_crop_bottom;
    img->p_width           = img->width  + 2 * IMG_PAD_SIZE;
    img->p_height          = img->height + 2 * IMG_PAD_SIZE;
    img->p_width_cr        = img->p_width  >> 1;
    img->p_height_cr       = img->p_height >> 1;
    img->mb_width          = img->width  >> 4;
    img->mb_height         = img->height >> 4;
    img->b8_width          = img->width  >> 3;
    img->b8_height         = img->height >> 3;
    img->total_mb_num      = img->mb_width * img->mb_height;
    img->width_cr          = img->width  >> 1;
    img->height_cr         = img->height >> 1;
    img->frame_rate        = ( int )frame_rate[input->frame_rate_code - 1];
    img->p_interval        = input->jumpd + 1;

    if ( input->slice_row_nr == 0 )
        input->slice_row_nr = img->mb_height;

    get_mem2D_byte( &img->org_y_data, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    get_mem2D_int( &img->y_residual, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    get_mem2D_int( &img->b8_residual, B8_SIZE, B8_SIZE );
    get_mem2D_int( &img->b16_residual, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    get_mem2D_byte( &img->mpr, MB_BLOCK_SIZE, MB_BLOCK_SIZE );
    for ( i=0; i<2; i++ )
    {
        get_mem2D_byte( &img->org_uv_data[i], B8_SIZE, B8_SIZE );
    }
    for ( i=0; i<2; i++ )
    {
        get_mem2D_int( &img->uv_residual[i], B8_SIZE, B8_SIZE );
    }
    get_mem2D_int( &img->cofAC16x16,257,2 );
    get_mem_ACcoeff( &( img->cofAC ) );
    get_mem_DCcoeff( &( img->cofDC ) );

    get_mem4D_int( &( img->chromacofAC ), 2, 4, 2, 17 );

    get_mem_ACcoeff( &( best_parameter.cofAC ) );
    get_mem2D_int( &best_parameter.cofAC16x16,257,2 );
    get_mem4D_int( &( best_parameter.chromacofAC ),2,4,2,17 );

    if ( ( img->mb_syntax_elements = ( syntax_element_t * ) calloc( ( img->total_mb_num + 1200 ), sizeof( syntax_element_t ) ) ) == NULL )
        no_mem_exit( "init_img: mb_syntax_elements" );

    if ( ( img->quad = ( int * )calloc( 511, sizeof( int ) ) ) == NULL )
        no_mem_exit( "init_img: img->quad" );

    img->quad += 255;

    for ( i = 0; i < 256; ++i )
    {
        img->quad[i] = img->quad[-i] = i * i;
    }

    if ( ( ( img->mb_data ) = ( macroblock_t * ) calloc( img->total_mb_num, sizeof( macroblock_t ) ) ) == NULL )
        no_mem_exit( "init_img: img->mb_data" );

    for ( i = 0; i < img->total_mb_num; i++ )
    {
        get_mem4D_int( &( img->mb_data[i].cofAC ), 6, 4, 2, 65 );
        get_mem4D_int( &( img->mb_data[i].chromacofAC ), 2, 4, 2, 17 );
    }

    for ( i = 0; i < ( img->total_mb_num ); i++ )
    {
        img->mb_data[i].slice_nr = 0;
    }
}
static void free_bs( bitstream_t *target_stream )
{
    if ( target_stream->stream_buffer )
    {
        free( target_stream->stream_buffer );
        free( target_stream );
    }
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void free_glb_buf()
{
    int i, j, refnum;
    free_mem2D_all( ( void ** )intra_pred );
    free_mem2D_all( ( void ** )inter_pred );
    free_mem2D_all( ( void ** )diffy );
    free_mem2D_all( ( void ** )img_y_org );
    free_mem3D_byte( img_uv_org, UV );
    for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
    {
        for ( j=0; j<img->height; j++ )
        {
            img_y_rec_space_offset[refnum][j] = NULL;
        }
        free( img_y_rec_space_offset[refnum] );
        free( img_y_rec_space[refnum] );
    }
    for ( refnum = 0; refnum < MAX_REF_NUM; refnum++ )
    {
#if QUARTER_PIXEL
        for ( i = 0; i < HALF_POS_NUM + QUATER_POS_NUM; i++ )
#else
        for ( i = 0; i < HALF_POS_NUM; i++ )
#endif
        {
            free( y_up_sampling[refnum][i] );
        }
    }
    for ( i = 0; i < UV; i++ )
    {
        for ( refnum = 0; refnum < MAX_REF_NUM_PLUS_1; refnum++ )
        {
            for ( j=0; j<img->height_cr; j++ )
            {
                img_uv_rec_space_offset[i][refnum][j] = NULL;
            }
            free( img_uv_rec_space_offset[i][refnum] );
            free( img_uv_rec_space[i][refnum] );
        }
    }
    for ( refnum=0; refnum<MAX_REF_NUM_PLUS_1; refnum++ )
    {
        free_mem2D_mv( frm_mv[refnum] );
        free_mem4D_mv( frm_mv_4x4[refnum], ( img->height )/8, ( img->width )/8 );
    }

    /*if (input->succe_b != 0)*/
    {
        free_mem2D_bi_mv( frm_bi_mv );
        free_mem4D_bi_mv( frm_bi_mv_4x4,( img->height )/8,( img->width )/8 );
#ifdef FastME
        if( input->UseFME == 1 )
        {
            free_mem4D_mv   ( last_frm_mv_4x4, ( img->height )/8, ( img->width )/8 );
            free_mem4D_mv   ( curr_frm_mv_4x4, ( img->height )/8, ( img->width )/8 );

            free_mem4D_bi_mv( last_frm_bi_mv_4x4,( img->height )/8,( img->width )/8 );
            free_mem4D_bi_mv( curr_frm_bi_mv_4x4,( img->height )/8,( img->width )/8 );
        }
#endif
    }

    free_mem2D_all( ( void ** )nextP_imgY );
    free_mem3D_byte( nextP_imgUV,2 );

#if DEBLOCK //added by ckj
    free_mem2D_all( ( void ** )p_img_y_rec_deblock );
    free_mem3D_byte( p_img_uv_rec_deblock,2 );
    free_mem2D_all( ( void ** )nextP_imgY_deblock );
    free_mem3D_byte( nextP_imgUV_deblock,2 );
#endif

    free( img->mb_data );
    free( allbelta_lum );
    free( allalpha_lum );
    free_bs( curr_stream );
    if ( input->rdopt )
    {
        free_bs( rdo_stream );
    }
}

static void free_qcoder()
{
    free( qcoder );
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void free_img()
{
    int i;
    free_mem2D_all( ( void ** )img->org_y_data );
    free_mem2D_all( ( void ** )img->y_residual );
    free_mem2D_all( ( void ** )img->mpr );
    free_mem2D_all( ( void ** )img->b8_residual );
    //free_mem2D_all(img->b4_residual);
    free_mem2D_all( ( void ** )img->b16_residual );
    for ( i=0; i<2; i++ )
    {
        free_mem2D_all( ( void ** )img->org_uv_data[i] );
        free_mem2D_all( ( void ** )img->uv_residual[i] );
    }

    free_mem4D_int( img->chromacofAC, 2, 4 );
    free( img->cofAC16x16 );
    free( best_parameter.cofAC16x16 );
    free_mem_ACcoeff( img->cofAC );
    free_mem4D_int( best_parameter.chromacofAC,2,4 );
    free_mem_ACcoeff( best_parameter.cofAC );
    //free_mem2D_all(img->cofAC16x16);
    free_mem_DCcoeff( img->cofDC );
    free( img->quad - 255 );
    free( img->mb_syntax_elements );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void encode_init()
{
    p_log = NULL;

    init_img();
    init_rdopt();
    init_glb_buf();
    init_me_module();
    init_infor();
    init_mv_range();
    init_qcoder();

    curr_stream = alloc_bitstream();
    if ( input->rdopt )
    {
        rdo_stream = alloc_bitstream();
    }
    if ( input->rc_enable )
        init_seq_rc();

    tot_time                   = 0;
    tot_metime                 = 0;
    tot_b_frm_num              = 0;
    img->seq_header_flag       = 1;
    img->encode_end_flag       = 0;
    tmp_buf_cycle              = img->buf_cycle;
    if ( input->rc_enable )
    {
        p_bbv = init_bbv_memory( input );
    }
    me     = blk_me;
    me_bid = blk_me_bid;
#ifdef FastME
    if ( input->UseFME )
    {
        get_mem_FME();
        DefineThreshold();
    }
#endif
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void report()
{
#if SYNTAX_STAT 
	int total_syntax_bits[3];
#endif
    int bit_use[2][2];
    int i, j;
    char name[20];
    int bit_use_Bframe = 0;
    int total_bits;
    float frame_rate;
    float mean_motion_info_bit_use[2] = {0.0, 0.0};

    int no_IPframes = ( input->no_frames + input->succe_b - 1 ) / ( input->succe_b + 1 ) + 1;

#if defined(WIN32) && !defined(__MINGW32__)
    char timebuf[128];
#else
    time_t now;
    struct tm *l_time;
    char string[1000];
#endif

    FILE *p_stat;
    if ( input->intra_period )
        bit_use[0][0] = 1 + ( no_IPframes - 1 ) / input->intra_period;
    else
        bit_use[0][0] = 1;
    bit_use[1][0] = RFM_MAX( 1, no_IPframes - bit_use[0][0] );

    bit_use[0][1] = bit_use[1][1] = 0;

    for ( i = 0; i < 11; i++ )
        bit_use[1][1] += stat->bit_use_mode_inter[0][i];

    for ( j = 0; j < 2; j++ )
    {
        bit_use[j][1] += stat->bit_use_header[j];
        bit_use[j][1] += stat->bit_use_mb_type[j];
        bit_use[j][1] += stat->bit_use_cbp[j];
        bit_use[j][1] += stat->bit_use_coeff_y[j];
        bit_use[j][1] += stat->bit_use_coeff_c[j];
        bit_use[j][1] += stat->bit_use_delta_quant[j];
        bit_use[j][1] += stat->bit_use_stuff_bits[j];
    }

    if ( tot_b_frm_num != 0 )
    {
        bit_use_Bframe = 0;
        for ( i = 0; i < 11; i++ )
            bit_use_Bframe += stat->bit_use_mode_inter[1][i];
        bit_use_Bframe += stat->bit_use_header[2];
        bit_use_Bframe += stat->bit_use_mb_type[2];
        bit_use_Bframe += stat->bit_use_cbp[2];
        bit_use_Bframe += stat->bit_use_coeff_y[2];
        bit_use_Bframe += stat->bit_use_coeff_c[2];
        bit_use_Bframe += stat->bit_use_delta_quant[2];
        bit_use_Bframe += stat->bit_use_stuff_bits[2];

        stat->bitrate_P = ( stat->bit_ctr_0 + stat->bit_ctr_P ) * ( float )( img->frame_rate / ( input->jumpd + 1 ) ) / no_IPframes;
        stat->bitrate_B = ( stat->bit_ctr_B ) * ( float )( img->frame_rate / ( input->jumpd + 1 ) ) * input->succe_b / tot_b_frm_num;
    }


    fprintf( stdout, "-----------------------------------------------------------------------------\n" );
    fprintf( stdout, " Freq. for encoded bitstream       : %1.0f\n", ( float )( img->frame_rate * ( input->succe_b + 1 ) ) / ( float )( input->jumpd + 1 ) );
    fprintf( stdout, " Image (Encoding) format           : %dx%d\n", img->width, img->height );
    fprintf( stdout, " Image (Recon) format              : %dx%d\n", ( img->width - img->auto_crop_right ), ( img->height - img->auto_crop_bottom ) );

    if ( input->intra_upd )
        fprintf( stdout, " Error robustness                  : On\n" );
    else
        fprintf( stdout, " Error robustness                  : Off\n" );
    fprintf( stdout, " Search range                      : %d\n", input->search_range );

    fprintf( stdout, " Skip Marcoblock Coding            : %s\n", input->skip_mode_flag == 0 ? "Off" : "On" );

    fprintf( stdout, " Total encoding time for the seq.  : %.3f sec \n", tot_time * 0.001 );

    fprintf( stdout, " Total ME time for the seq.        : %.3f sec \n", tot_metime * 0.001 );


    fprintf( stdout, " Sequence type                     :" );

    if ( input->succe_b == 1 )
        fprintf( stdout, " IBPBP (QP: I %d, P %d, B %d) \n", input->qp_first, input->qp_p, input->qp_b );
    else if ( input->succe_b == 2 )
        fprintf( stdout, " IBBPBBP (QP: I %d, P %d, B %d) \n", input->qp_first, input->qp_p, input->qp_b );
    else if ( input->succe_b == 0 && input->intra_period != 1 )
        fprintf( stdout, " IPPP (QP: I %d, P %d) \n", input->qp_first, input->qp_p );
    else if ( input->succe_b == 0 && input->intra_period == 1 )
        fprintf( stdout, " IPPP (QP: I %d) \n", input->qp_first );

    fprintf( stdout, " Entropy coding method             : Qcoder\n" );
    if ( input->rdopt )
        fprintf( stdout, " RD-optimized mode decision        : used\n" );
    else
        fprintf( stdout, " RD-optimized mode decision        : not used\n" );

    fprintf( stdout, "------------------ Average data all frames  ---------------------------------\n" );
    fprintf( stdout, " SNR Y(dB)                         : %5.2f\n", snr->snr_ya );
    fprintf( stdout, " SNR U(dB)                         : %5.2f\n", snr->snr_ua );
    fprintf( stdout, " SNR V(dB)                         : %5.2f\n", snr->snr_va );

    if ( tot_b_frm_num != 0 )
    {
        fprintf( stdout, " Total bits                        : %d (I %5d, P %5d, B %d) \n", total_bits = stat->bit_ctr_P + stat->bit_ctr_0 + stat->bit_ctr_B, stat->bit_ctr_0, stat->bit_ctr_P, stat->bit_ctr_B );

        frame_rate = ( float )( img->frame_rate * ( input->succe_b + 1 ) ) / ( float )( input->jumpd + 1 );
        stat->bitrate = ( ( float )total_bits * frame_rate ) / ( ( float )( input->no_frames ) );

        fprintf( stdout, " Bit rate (kbit/s)  @ %2.2f Hz     : %5.2f\n", frame_rate, stat->bitrate / 1000 );
    }
    else
    {
        fprintf( stdout, " Total bits                        : %d (I %5d, P %5d) \n", total_bits = stat->bit_ctr_P + stat->bit_ctr_0, stat->bit_ctr_0, stat->bit_ctr_P );

        frame_rate = ( float )img->frame_rate / ( ( float )( input->jumpd + 1 ) );
        stat->bitrate = ( ( float )total_bits * frame_rate ) / ( ( float )input->no_frames );

        fprintf( stdout, " Bit rate (kbit/s)  @ %2.2f Hz     : %5.2f\n", frame_rate, stat->bitrate / 1000 );
    }

    fprintf( stdout, " Bits to avoid Startcode Emulation : %d \n", stat->bit_ctr_emulationprevention );
    fprintf( stdout, "-----------------------------------------------------------------------------\n" );
    fprintf( stdout, "Exit RFM encoder ver %s ", VERSION );
    fprintf( stdout, "\n\n" );

    if ( ( p_stat = fopen( "stat.dat", "w" ) ) == NULL )
    {
        snprintf( error_text, ET_SIZE, "Error open file %s", "stat.dat" );
        error( error_text, 500 );
    }

    fprintf( p_stat, "\n ------------------ Average data all frames  ------------------------------\n" );
    fprintf( p_stat, " SNR Y(dB)                         : %5.2f\n", snr->snr_ya );
    fprintf( p_stat, " SNR U(dB)                         : %5.2f\n", snr->snr_ua );
    fprintf( p_stat, " SNR V(dB)                         : %5.2f\n", snr->snr_va );
    fprintf( p_stat, " Total bits                        : %d (I %5d, P BS %5d, B %d) \n", total_bits = stat->bit_ctr_P + stat->bit_ctr_0 + stat->bit_ctr_B, stat->bit_ctr_0, stat->bit_ctr_P, stat->bit_ctr_B );

    fprintf( p_stat, " Bit rate (kbit/s)  @ %2.2f Hz     : %5.2f\n", frame_rate, stat->bitrate / 1000 );
    fprintf( p_stat, " -------------------------------------------------------------- \n" );
    fprintf( p_stat, "  This file contains statistics for the last encoded sequence   \n" );
    fprintf( p_stat, " -------------------------------------------------------------- \n" );
    fprintf( p_stat, " Sequence                     : %s\n", input->in_file );
    fprintf( p_stat, " No.of coded pictures         : %4d\n", input->no_frames );
    fprintf( p_stat, " Freq. for encoded bitstream  : %4.0f\n", frame_rate );

    if ( input->succe_b != 0 )
    {
        fprintf( p_stat, " IPFrame Bitrate(kb/s)      : %6.2f\n", stat->bitrate_P / 1000 );
        fprintf( p_stat, " BFrame Bitrate(kb/s)  : %6.2f\n", stat->bitrate_B / 1000 );
    }
    else
        fprintf( p_stat, " Bitrate(kb/s)                : %6.2f\n", stat->bitrate / 1000 );

    fprintf( p_stat, " Image format                 : %dx%d\n", img->width, img->height );

    if ( input->intra_upd )
        fprintf( p_stat, " Error robustness             : On\n" );
    else
        fprintf( p_stat, " Error robustness             : Off\n" );

    fprintf( p_stat, " Search range                 : %d\n", input->search_range );
    fprintf( stdout, " Entropy coding method             : Qcoder\n" );
    fprintf( p_stat, " Search range restrictions    : none\n" );

    if ( input->rdopt )
        fprintf( p_stat, " RD-optimized mode decision   : used\n" );
    else
        fprintf( p_stat, " RD-optimized mode decision   : not used\n" );

    fprintf( p_stat, " -------------------|---------------|---------------|\n" );
    fprintf( p_stat, "     Item           |     Intra     |   All frames  |\n" );
    fprintf( p_stat, " -------------------|---------------|---------------|\n" );
    fprintf( p_stat, " SNR Y(dB)          |" );
    fprintf( p_stat, " %5.2f         |", snr->snr_y1 );
    fprintf( p_stat, " %5.2f         |\n", snr->snr_ya );
    fprintf( p_stat, " SNR U/V (dB)       |" );
    fprintf( p_stat, " %5.2f/%5.2f   |", snr->snr_u1, snr->snr_v1 );
    fprintf( p_stat, " %5.2f/%5.2f   |\n", snr->snr_ua, snr->snr_va );

    fprintf( p_stat, " Average quant      |" );
    fprintf( p_stat, " %5d         |", RFM_ABS( input->qp_first ) );

    fprintf( p_stat, "\n -------------------|---------------|\n" );
    fprintf( p_stat, "   Intra            | Mode used(MBs)|\n" );
    fprintf( p_stat, " -------------------|---------------|\n" );
    fprintf( p_stat, " Total MBs in I     | %7.1f       |\n", (float)stat->mode_use_intra[I8MB] );
    fprintf( p_stat, " Mode 0  intra8x8   | %7.1f       |\n", stat->mode_use_intra[SUBBLOCK_INTRA8x8]/4.0);
    fprintf( p_stat, " Mode 1  intra4x4   | %7.1f       |\n", stat->mode_use_intra[SUBBLOCK_INTRA4x4]*4.0/16.0);
    fprintf( p_stat, "\n ------------------------|---------------|-----------------|\n" );
    fprintf( p_stat, "   Inter P Frames        | Mode used(MBs)| MotionInfo bits(bits/frame) |\n" );
    fprintf( p_stat, " ------------------------|---------------|-----------------|" );
    fprintf( p_stat, "\n Mode  0  (skip)         | %5d         |    %8.2f     |", stat->mode_use_inter_changed[0][STAT_SKIP], ( float )stat->bit_use_mode_inter[0][0] / ( float )bit_use[1][0] );
    fprintf( p_stat, "\n Mode  1  (inter16x16)   | %5d         |    %8.2f     |", stat->mode_use_inter_changed[0][STAT_INTER16X16], ( float )stat->bit_use_mode_inter[0][1] / ( float )bit_use[1][0] );
    //fprintf(p_stat, "\n Mode  2  (16x8)    | %5d         |    %8.2f     |", stat->mode_use_inter[0][3], (float)stat->bit_use_mode_inter[0][3] / (float)bit_use[1][0]);//xy_110915
    //fprintf(p_stat, "\n Mode  3  (8x16)    | %5d         |    %8.2f     |", stat->mode_use_inter[0][3], (float)stat->bit_use_mode_inter[0][3] / (float)bit_use[1][0]);
    fprintf( p_stat, "\n Mode  2  (inter8x8)     | %7.2f       |    %8.2f     |", stat->mode_use_inter_changed[0][STAT_INTER8X8]/4.0, ( float )stat->bit_use_mode_inter[0][INTER8x8/*modified by wyp*/] / ( float )bit_use[1][0] );
    //fprintf(p_stat, "\n Mode  5  intra     | %5d         |-----------------|", stat->mode_use_inter[0][I8MB]);
    fprintf( p_stat, "\n Mode  3  (intra8x8)     | %7.2f       |-----------------|", stat->mode_use_inter_changed[0][STAT_INTRA8X8]/4.0 );
    fprintf( p_stat, "\n Mode  4  (inter4x4)     | %7.2f       |", stat->mode_use_inter_changed[0][STAT_INTER4X4]/4.0 );
    fprintf( p_stat, "\n Mode  5  (intra4x4)     | %7.2f       |", stat->mode_use_inter_changed[0][STAT_INTRA4X4]/4.0 );
    fprintf( p_stat, "\n ------------------------|---------------|" );
    fprintf( p_stat, "\n Total MBs in P  Frame   | %7.2f       |", stat->mode_use_inter_changed[0][STAT_SKIP]         +stat->mode_use_inter_changed[0][STAT_INTER16X16]
                                                                   +stat->mode_use_inter_changed[0][STAT_INTER8X8]/4.0+stat->mode_use_inter_changed[0][STAT_INTRA8X8]/4.0
                                                                   +stat->mode_use_inter_changed[0][STAT_INTER4X4]/4.0+stat->mode_use_inter_changed[0][STAT_INTRA4X4]/4.0 );

    mean_motion_info_bit_use[0] = ( float )( stat->bit_use_mode_inter[0][0] + stat->bit_use_mode_inter[0][1] + stat->bit_use_mode_inter[0][3] + stat->bit_use_mode_inter[0][3] + stat->bit_use_mode_inter[0][INTER8x8/*modified by wyp*/] ) / ( float )bit_use[1][0]; //xy_110915

    fprintf( p_stat, "\n pred-direction in MB: P\n" );
    fprintf( p_stat, " 16x16   fw: %5d\n", stat->pred_direction_use[0][0][FW] );
    fprintf( p_stat, " 8x8     fw: %7.2f, intra: %7.2f\n", stat->pred_direction_use[0][1][FW]/4.0, stat->pred_direction_use[0][1][INTRA]/4.0 );
    fprintf( p_stat, " 4x4     fw: %7.2f, intra: %7.2f\n", stat->pred_direction_use[0][2][FW]/16.0, stat->pred_direction_use[0][2][INTRA]/16.0 );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
    {
        fprintf( p_stat, "\n\n ------------------------|---------------|-----------------|\n" );
        fprintf( p_stat, "   B frame               | Mode used(MBs)| MotionInfo bits(bits/frame) |\n" );
        fprintf( p_stat, " ------------------------|---------------|-----------------|" );
        fprintf( p_stat, "\n Mode  0  (skip)         | %5d         |    %8.2f     |", stat->mode_use_inter_changed[1][STAT_SKIP], ( float )stat->bit_use_mode_inter[1][0] / ( float )tot_b_frm_num );
        fprintf( p_stat, "\n Mode  1  (inter16x16)   | %5d         |    %8.2f     |", stat->mode_use_inter_changed[1][STAT_INTER16X16], ( float )stat->bit_use_mode_inter[1][1] / ( float )tot_b_frm_num );
        //fprintf(p_stat, "\n Mode  2  (16x8)    | %5d         |    %8.2f     |", stat->mode_use_inter[0][3], (float)stat->bit_use_mode_inter[0][3] / (float)bit_use[1][0]);//xy_110915
        //fprintf(p_stat, "\n Mode  3  (8x16)    | %5d         |    %8.2f     |", stat->mode_use_inter[0][3], (float)stat->bit_use_mode_inter[0][3] / (float)bit_use[1][0]);
        fprintf( p_stat, "\n Mode  2  (inter8x8)     | %7.2f         |    %8.2f   |", stat->mode_use_inter_changed[1][STAT_INTER8X8]/4.0, ( float )stat->bit_use_mode_inter[1][INTER8x8/*modified by wyp*/] / ( float )tot_b_frm_num );
        //fprintf(p_stat, "\n Mode  5  intra     | %5d         |-----------------|", stat->mode_use_inter[0][I8MB]);
        fprintf( p_stat, "\n Mode  3  (intra8x8)     | %7.2f         |-----------------|", stat->mode_use_inter_changed[1][STAT_INTRA8X8]/4.0 );
        fprintf( p_stat, "\n Mode  4  (inter4x4)     | %7.2f         |", stat->mode_use_inter_changed[1][STAT_INTER4X4]/4.0 );
        fprintf( p_stat, "\n Mode  5  (intra4x4)     | %7.2f         |", stat->mode_use_inter_changed[1][STAT_INTRA4X4]/4.0 );
        fprintf( p_stat, "\n ------------------------|---------------|" );
        fprintf( p_stat, "\n Total MBs in B Frame    | %7.2f       |", stat->mode_use_inter_changed[1][STAT_SKIP]     +stat->mode_use_inter_changed[1][STAT_INTER16X16]
                                                                   +stat->mode_use_inter_changed[1][STAT_INTER8X8]/4.0+stat->mode_use_inter_changed[1][STAT_INTRA8X8]/4.0
                                                                   +stat->mode_use_inter_changed[1][STAT_INTER4X4]/4.0+stat->mode_use_inter_changed[1][STAT_INTRA4X4]/4.0 );

        mean_motion_info_bit_use[1] = ( float )( stat->bit_use_mode_inter[1][0] + stat->bit_use_mode_inter[1][1] + stat->bit_use_mode_inter[1][3] + stat->bit_use_mode_inter[1][3] + stat->bit_use_mode_inter[1][INTER8x8/*modified by wyp*/] ) / ( float )tot_b_frm_num; //xy_110915

        fprintf( p_stat, "\n pred-direction: B\n" );
        fprintf( p_stat, " 16x16   fw: %5d, bw: %5d, bi: %5d\n", stat->pred_direction_use[1][0][FW], stat->pred_direction_use[1][0][BW], stat->pred_direction_use[1][0][BI] );
        fprintf( p_stat, " 8x8     fw: %7.2f, bw: %7.2f, bi: %7.2f, intra: %7.2f\n", stat->pred_direction_use[1][1][FW]/4.0, stat->pred_direction_use[1][1][BW]/4.0, stat->pred_direction_use[1][1][BI]/4.0, stat->pred_direction_use[1][1][INTRA]/4.0 );
        fprintf( p_stat, " 4x4     fw: %7.2f, bw: %7.2f, bi: %7.2f, intra: %7.2f\n", stat->pred_direction_use[1][2][FW]/16.0, stat->pred_direction_use[1][2][BW]/16.0, stat->pred_direction_use[1][2][BI]/16.0, stat->pred_direction_use[1][2][INTRA]/16.0 );
    }

    fprintf( p_stat, "\n\n --------------------|----------------|----------------|----------------|\n" );
    fprintf( p_stat, "  Bit usage:         |      Intra     |      Inter     |    B frame     |\n" );
    fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );
    fprintf( p_stat, " Header              |" );
    fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_header[0] / bit_use[0][0] );
    fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_header[1] / bit_use[1][0] );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_header[2] / tot_b_frm_num );
    else
        fprintf( p_stat, " %10.2f     |", 0. );

    fprintf( p_stat, "\n" );
    fprintf( p_stat, " Mode                |" );
    fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_mb_type[0] / bit_use[0][0] );
    fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_mb_type[1] / bit_use[1][0] );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_mb_type[2] / tot_b_frm_num );
    else
        fprintf( p_stat, " %10.2f     |", 0. );

    fprintf( p_stat, "\n" );
    fprintf( p_stat, " Motion Info         |" );
    fprintf( p_stat, "        ./.     |" );
    fprintf( p_stat, " %10.2f     |", mean_motion_info_bit_use[0] );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " %10.2f     |", mean_motion_info_bit_use[1] );
    else
        fprintf( p_stat, " %10.2f     |", 0. );

    fprintf( p_stat, "\n" );
    fprintf( p_stat, " CBP Y/C             |" );

    for ( j = 0; j < 2; j++ )
    {
        // fprintf(p_stat, " %10.2f     |", (float)stat->bit_use_cbp[j] / bit_use[j][0]);
        fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_cbp[j] ); //xy_4x4test
    }

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        //fprintf(p_stat, " %10.2f     |", (float)stat->bit_use_cbp[2] / tot_b_frm_num);
        fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_cbp[2] ); //xy_4x4test
    else
        fprintf( p_stat, " %10.2f     |", 0. );

    fprintf( p_stat, "\n" );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " Coeffs. Y           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_y[0] / bit_use[0][0], ( float )stat->bit_use_coeff_y[1] / bit_use[1][0], ( float )stat->bit_use_coeff_y[2] / tot_b_frm_num );
    else
        fprintf( p_stat, " Coeffs. Y           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_y[0] / bit_use[0][0], ( float )stat->bit_use_coeff_y[1] / ( float )bit_use[1][0], 0. );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " Coeffs. C           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_c[0] / bit_use[0][0], ( float )stat->bit_use_coeff_c[1] / bit_use[1][0], ( float )stat->bit_use_coeff_c[2] / tot_b_frm_num );
    else
        fprintf( p_stat, " Coeffs. C           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_c[0] / bit_use[0][0], ( float )stat->bit_use_coeff_c[1] / bit_use[1][0], 0. );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        //fprintf(p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", (float)stat->bit_use_delta_quant[0] / bit_use[0][0], (float)stat->bit_use_delta_quant[1] / bit_use[1][0], (float)stat->bit_use_delta_quant[2] / tot_b_frm_num);
        fprintf( p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_delta_quant[0] , ( float )stat->bit_use_delta_quant[1] , ( float )stat->bit_use_delta_quant[2] );
    else
        //fprintf(p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", (float)stat->bit_use_delta_quant[0] / bit_use[0][0], (float)stat->bit_use_delta_quant[1] / bit_use[1][0], 0.);
        fprintf( p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_delta_quant[0] , ( float )stat->bit_use_delta_quant[1] , 0. );

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " Stuffing Bits       | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_stuff_bits[0] / bit_use[0][0], ( float )stat->bit_use_stuff_bits[1] / bit_use[1][0], ( float )stat->bit_use_stuff_bits[2] / tot_b_frm_num );
    else
        fprintf( p_stat, " Stuffing Bits       | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_stuff_bits[0] / bit_use[0][0], ( float )stat->bit_use_stuff_bits[1] / bit_use[1][0], 0. );

    fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );
    fprintf( p_stat, " average bits/frame  |" );

    for ( i = 0; i < 2; i++ )
    {
        fprintf( p_stat, " %10.2f     |", ( float )bit_use[i][1] / ( float )bit_use[i][0] );
    }

    if ( input->succe_b != 0 && tot_b_frm_num != 0 )
        fprintf( p_stat, " %10.2f     |", ( float )bit_use_Bframe / ( float )tot_b_frm_num );
    else
        fprintf( p_stat, " %10.2f     |", 0. );

    fprintf( p_stat, "\n" );
    fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );

#if SYNTAX_STAT
	for(i=0;i<3;i++)
	{
		total_syntax_bits[i] =  stat->bit_use_header[i] +
							    stat->bit_use_mb_type[i] +
								stat->bit_use_coeff_y[i]+
								stat->bit_use_coeff_c[i];
		if(i>0)
		{
			total_syntax_bits[i] += mean_motion_info_bit_use[i-1];
		}
	}
	fprintf( p_stat, "\n\n --------------------|----------------|----------------|----------------|\n" );
	fprintf( p_stat, "  Bit usage:         |      Intra     |      Inter     |    B frame     |\n" );
	fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );
	fprintf( p_stat, " Header              |" );
	fprintf( p_stat, " %10.2f(%3.1f%%)|", ( float )stat->bit_use_header[0], (float)stat->bit_use_header[0]/(float)total_syntax_bits[0]*100);
	fprintf( p_stat, " %10.2f(%3.1f%%)|", ( float )stat->bit_use_header[1],(float)stat->bit_use_header[1]/(float)total_syntax_bits[1]*100 );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " %10.2f(%3.1f%%)|", ( float )stat->bit_use_header[2],(float)stat->bit_use_header[2]/(float)total_syntax_bits[2]*100 );
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );
	fprintf( p_stat, " Mode                |" );
	fprintf( p_stat, " %10.2f(%3.1f%%)|", ( float )stat->bit_use_mb_type[0],( float )stat->bit_use_mb_type[0]/(float)total_syntax_bits[0]*100 );
	fprintf( p_stat, " %10.2f(%3.1f%%)|", ( float )stat->bit_use_mb_type[1],( float )stat->bit_use_mb_type[1]/(float)total_syntax_bits[1]*100 );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " %10.2f(%3.1f%%)|", ( float )stat->bit_use_mb_type[2],( float )stat->bit_use_mb_type[2]/(float)total_syntax_bits[2]*100 );
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );
	fprintf( p_stat, " Motion Info         |" );
	fprintf( p_stat, "        ./.     |" );
	fprintf( p_stat, " %10.2f(%3.1f%%)|", mean_motion_info_bit_use[0], (float)mean_motion_info_bit_use[0]/(float)total_syntax_bits[1]*100);

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " %10.2f(%3.1f%%)|", mean_motion_info_bit_use[1],(float)mean_motion_info_bit_use[1]/(float)total_syntax_bits[2]*100 );
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );
	fprintf( p_stat, " CBP Y/C             |" );

	for ( j = 0; j < 2; j++ )
	{
		// fprintf(p_stat, " %10.2f     |", (float)stat->bit_use_cbp[j] / bit_use[j][0]);
		fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_cbp[j] ); //xy_4x4test
	}

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		//fprintf(p_stat, " %10.2f     |", (float)stat->bit_use_cbp[2] / tot_b_frm_num);
		fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_cbp[2] ); //xy_4x4test
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " Coeffs. Y           | %5.2f(%3.1f%%)| %10.2f(%3.1f%%)| %10.2f(%3.1f%%)|\n", ( float )stat->bit_use_coeff_y[0], ( float )stat->bit_use_coeff_y[0]/(float)total_syntax_bits[0]*100,
																							( float )stat->bit_use_coeff_y[1], ( float )stat->bit_use_coeff_y[1]/(float)total_syntax_bits[1]*100,
																							( float )stat->bit_use_coeff_y[2], ( float )stat->bit_use_coeff_y[2]/(float)total_syntax_bits[2]*100 );
	else
		fprintf( p_stat, " Coeffs. Y           | %5.2f(%3.1f%%)| %10.2f(%3.1f%%)| %10.2f(%3.1f%%)|\n", ( float )stat->bit_use_coeff_y[0],( float )stat->bit_use_coeff_y[0]/(float)total_syntax_bits[0]*100,
																							( float )stat->bit_use_coeff_y[1], ( float )stat->bit_use_coeff_y[1]/(float)total_syntax_bits[1]*100,
																							0., 0. );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " Coeffs. C           | %5.2f(%3.1f%%)| %10.2f(%3.1f%%)| %10.2f(%3.1f%%)|\n", ( float )stat->bit_use_coeff_c[0], ( float )stat->bit_use_coeff_c[0]/(float)total_syntax_bits[0]*100,
		( float )stat->bit_use_coeff_c[1], ( float )stat->bit_use_coeff_c[1]/(float)total_syntax_bits[1]*100,
		( float )stat->bit_use_coeff_c[2], ( float )stat->bit_use_coeff_c[2]/(float)total_syntax_bits[2]*100 );
	else
		fprintf( p_stat, " Coeffs. C           | %5.2f(%3.1f%%)| %10.2f(%3.1f%%)| %10.2f(%3.1f%%)|\n", ( float )stat->bit_use_coeff_c[0], ( float )stat->bit_use_coeff_c[0]/(float)total_syntax_bits[0]*100,
		( float )stat->bit_use_coeff_c[1], ( float )stat->bit_use_coeff_c[1]/(float)total_syntax_bits[1]*100,
		0.,0. );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		//fprintf(p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", (float)stat->bit_use_delta_quant[0] / bit_use[0][0], (float)stat->bit_use_delta_quant[1] / bit_use[1][0], (float)stat->bit_use_delta_quant[2] / tot_b_frm_num);
		fprintf( p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_delta_quant[0] , ( float )stat->bit_use_delta_quant[1] , ( float )stat->bit_use_delta_quant[2] );
	else
		//fprintf(p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", (float)stat->bit_use_delta_quant[0] / bit_use[0][0], (float)stat->bit_use_delta_quant[1] / bit_use[1][0], 0.);
		fprintf( p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_delta_quant[0] , ( float )stat->bit_use_delta_quant[1] , 0. );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " Stuffing Bits       | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_stuff_bits[0], ( float )stat->bit_use_stuff_bits[1], ( float )stat->bit_use_stuff_bits[2] );
	else
		fprintf( p_stat, " Stuffing Bits       | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_stuff_bits[0], ( float )stat->bit_use_stuff_bits[1], 0. );

	fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );
#endif
    fclose( p_stat );

    if ( ( p_log = fopen( "log.dat", "r" ) ) == 0 )
    {
        if ( ( p_log = fopen( "log.dat", "a" ) ) == NULL )
        {
            snprintf( error_text, ET_SIZE, "Error open file %s  \n", "log.dat" );
            error( error_text, 500 );
        }
        else
        {
            fprintf( p_log, " ----------------------------------------------------------------------------------------------------------------------------------------------------------------- \n" );
            fprintf( p_log, "|            Encoder statistics. This file is generated during first encoding session, new sessions will be appended                                              |\n" );
            fprintf( p_log, " ----------------------------------------------------------------------------------------------------------------------------------------------------------------- \n" );
            fprintf( p_log, "| Date  | Time  |    Sequence        |#Img|Quant1|QuantN|Format|Hadamard|Search r|#Ref | Freq |Intra upd|SNRY 1|SNRU 1|SNRV 1|SNRY N|SNRU N|SNRV N|#Bitr P|#Bitr B|\n" );
            fprintf( p_log, " ----------------------------------------------------------------------------------------------------------------------------------------------------------------- \n" );
        }
    }
    else
    {
        fclose( p_log );
        if ( ( p_log = fopen( "log.dat", "a" ) ) == NULL )
        {
            snprintf( error_text, ET_SIZE, "Error open file %s  \n", "log.dat" );
            error( error_text, 500 );
        }
    }

#if defined(WIN32) && !defined(__MINGW32__)
    _strdate( timebuf );
    fprintf( p_log, "| %1.5s |", timebuf );

    _strtime( timebuf );
    fprintf( p_log, " % 1.5s |", timebuf );
#else
    now = time( ( time_t * ) NULL );
    time( &now );
    l_time = localtime( &now );
    strftime( string, sizeof string, "%d-%b-%Y", l_time );
    fprintf( p_log, "| %1.5s |", string );

    strftime( string, sizeof string, "%H:%M:%S", l_time );
    fprintf( p_log, " %1.5s |", string );
#endif

    for ( i = 0; i < 20; i++ )
        name[i] = input->in_file[i + RFM_MAX( 0, strlen( input->in_file ) - 20 )];

    fprintf( p_log, "%20.20s|", name );
    fprintf( p_log, "%3d |", input->no_frames );
    fprintf( p_log, "  %2d  |", input->qp_first );
    fprintf( p_log, "  %2d  |", input->qp_p );
    fprintf( p_log, "%dx%d|", img->width, img->height );

    fprintf( p_log, "   %2d   |", input->search_range );
    fprintf( p_log, " %2d  |", img->frame_rate / ( input->jumpd + 1 ) );

    if ( input->intra_upd == 1 )
        fprintf( p_log, "   ON    |" );
    else
        fprintf( p_log, "   OFF   |" );

    fprintf( p_log, "%5.3f|", snr->snr_y1 );
    fprintf( p_log, "%5.3f|", snr->snr_u1 );
    fprintf( p_log, "%5.3f|", snr->snr_v1 );
    fprintf( p_log, "%5.3f|", snr->snr_ya );
    fprintf( p_log, "%5.3f|", snr->snr_ua );
    fprintf( p_log, "%5.3f|", snr->snr_va );
	{
		FILE *fp=fopen("psnr.txt","a");
		fprintf(fp,"%7.2f,%5.3f %5.3f %5.3f\n",stat->bitrate,snr->snr_ya,snr->snr_ua,snr->snr_va);
		fclose(fp);
	}
    if ( input->succe_b != 0 )
    {
        fprintf( p_log, "%7.0f|", stat->bitrate_P );
        fprintf( p_log, "%7.0f|\n", stat->bitrate_B );
    }
    else
    {
        fprintf( p_log, "%7.0f|", stat->bitrate );
        fprintf( p_log, "%7.0f|\n", 0.0 );
    }
    fclose( p_log );
}
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
#if SYNTAX_STAT
static void report_one_frame()
{
	int bit_use[2][2];
	int i, j;
	int bit_use_Bframe = 0;
	int total_bits;
	float frame_rate;
	float mean_motion_info_bit_use[2] = {0.0, 0.0};
	static stat_t stat_pre;

	int no_IPframes = ( input->no_frames + input->succe_b - 1 ) / ( input->succe_b + 1 ) + 1;


	FILE *p_stat;


	if( img->tr == 0)
	{
		for( i = 0; i < 3; i++)
		{
			stat_pre.bit_use_header[i] = 0;
			stat_pre.bit_use_stuff_bits[i] = 0;
			stat_pre.bit_use_cbp[i] = 0;
			stat_pre.bit_use_coeff_c[i] = 0;
			stat_pre.bit_use_coeff_y[i] = 0;
			stat_pre.bit_use_mb_type[i] = 0;
			stat_pre.bit_use_delta_quant[i] = 0;
			stat_pre.bit_use_mode_inter[0][i] = 0;
		}
	}
	if ( input->intra_period )
		bit_use[0][0] = 1 + ( no_IPframes - 1 ) / input->intra_period;
	else
		bit_use[0][0] = 1;
	bit_use[1][0] = RFM_MAX( 1, no_IPframes - bit_use[0][0] );

	bit_use[0][1] = bit_use[1][1] = 0;

	for ( i = 0; i < 11; i++ )
		bit_use[1][1] += stat->bit_use_mode_inter[0][i];

	for ( j = 0; j < 2; j++ )
	{
		bit_use[j][1] += stat->bit_use_header[j];
		bit_use[j][1] += stat->bit_use_mb_type[j];
		bit_use[j][1] += stat->bit_use_cbp[j];
		bit_use[j][1] += stat->bit_use_coeff_y[j];
		bit_use[j][1] += stat->bit_use_coeff_c[j];
		bit_use[j][1] += stat->bit_use_delta_quant[j];
		bit_use[j][1] += stat->bit_use_stuff_bits[j];
	}

	if ( tot_b_frm_num != 0 )
	{
		bit_use_Bframe = 0;
		for ( i = 0; i < 11; i++ )
			bit_use_Bframe += stat->bit_use_mode_inter[1][i];
		bit_use_Bframe += stat->bit_use_header[2];
		bit_use_Bframe += stat->bit_use_mb_type[2];
		bit_use_Bframe += stat->bit_use_cbp[2];
		bit_use_Bframe += stat->bit_use_coeff_y[2];
		bit_use_Bframe += stat->bit_use_coeff_c[2];
		bit_use_Bframe += stat->bit_use_delta_quant[2];
		bit_use_Bframe += stat->bit_use_stuff_bits[2];

		stat->bitrate_P = ( stat->bit_ctr_0 + stat->bit_ctr_P ) * ( float )( img->frame_rate / ( input->jumpd + 1 ) ) / no_IPframes;
		stat->bitrate_B = ( stat->bit_ctr_B ) * ( float )( img->frame_rate / ( input->jumpd + 1 ) ) * input->succe_b / tot_b_frm_num;
	}
	if ( tot_b_frm_num != 0 )
	{	
		total_bits = stat->bit_ctr_P + stat->bit_ctr_0 + stat->bit_ctr_B;
		frame_rate = ( float )( img->frame_rate * ( input->succe_b + 1 ) ) / ( float )( input->jumpd + 1 );
		stat->bitrate = ( ( float )total_bits * frame_rate ) / ( ( float )( input->no_frames ) );
	}
	else
	{
		total_bits = stat->bit_ctr_P + stat->bit_ctr_0;
		frame_rate = ( float )img->frame_rate / ( ( float )( input->jumpd + 1 ) );
		stat->bitrate = ( ( float )total_bits * frame_rate ) / ( ( float )input->no_frames );
	}
	if ( ( p_stat = fopen( "stat_frame.dat", "a+" ) ) == NULL )
	{
		snprintf( error_text, ET_SIZE, "Error open file %s", "stat.dat" );
		error( error_text, 500 );
	}

	mean_motion_info_bit_use[0] = ( float )( stat->bit_use_mode_inter[0][0] + stat->bit_use_mode_inter[0][1] + stat->bit_use_mode_inter[0][3] + stat->bit_use_mode_inter[0][3] + stat->bit_use_mode_inter[0][INTER8x8/*modified by wyp*/] ); //xy_110915
	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
	{
		mean_motion_info_bit_use[1] = ( float )( stat->bit_use_mode_inter[1][0] + stat->bit_use_mode_inter[1][1] + stat->bit_use_mode_inter[1][3] + stat->bit_use_mode_inter[1][3] + stat->bit_use_mode_inter[1][INTER8x8/*modified by wyp*/] ) ; //xy_110915
	}

	fprintf( p_stat, "\n ------------------------Frame No.%d-------------------------------\n", img->tr );
	fprintf( p_stat, "\n\n --------------------|----------------|----------------|----------------|\n" );
	fprintf( p_stat, "  Bit usage:         |      Intra     |      Inter     |    B frame     |\n" );
	fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );
	fprintf( p_stat, " Header              |" );
	fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_header[0] - ( float )stat_pre.bit_use_header[0] );
	fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_header[1] - ( float )stat_pre.bit_use_header[1] );
	stat_pre.bit_use_header[0] = ( float )stat->bit_use_header[0];
	stat_pre.bit_use_header[1] = ( float )stat->bit_use_header[1];
	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
	{
		fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_header[2] - ( float )stat_pre.bit_use_header[2]  );
		stat_pre.bit_use_header[2] = ( float )stat->bit_use_header[2];
	}
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );
	fprintf( p_stat, " Mode                |" );
	fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_mb_type[0] - ( float )stat_pre.bit_use_mb_type[0]  );
	fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_mb_type[1] - ( float )stat_pre.bit_use_mb_type[1]  );
	stat_pre.bit_use_mb_type[0] = stat->bit_use_mb_type[0];
	stat_pre.bit_use_mb_type[1] = stat->bit_use_mb_type[1];
	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
	{
		fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_mb_type[2] - ( float )stat_pre.bit_use_mb_type[2] );
		stat_pre.bit_use_mb_type[2] = stat->bit_use_mb_type[2];
	}
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );
	fprintf( p_stat, " Motion Info         |" );
	fprintf( p_stat, "        ./.     |" );
	fprintf( p_stat, " %10.2f     |", mean_motion_info_bit_use[0]-stat_pre.bit_use_mode_inter[0][1] );
	stat_pre.bit_use_mode_inter[0][1]=mean_motion_info_bit_use[0];
	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
	{
		fprintf( p_stat, " %10.2f     |", mean_motion_info_bit_use[1]-stat_pre.bit_use_mode_inter[0][2] );
		stat_pre.bit_use_mode_inter[0][2]=mean_motion_info_bit_use[1];
	}
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );
	fprintf( p_stat, " CBP Y/C             |" );

	for ( j = 0; j < 2; j++ )
	{
		fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_cbp[j] ); 
	}

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " %10.2f     |", ( float )stat->bit_use_cbp[2] ); //xy_4x4test
	else
		fprintf( p_stat, " %10.2f     |", 0. );

	fprintf( p_stat, "\n" );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
	{
		fprintf( p_stat, " Coeffs. Y           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_y[0]-(float)stat_pre.bit_use_coeff_y[0] , ( float )stat->bit_use_coeff_y[1]-(float)stat_pre.bit_use_coeff_y[1] , ( float )stat->bit_use_coeff_y[2]-(float)stat_pre.bit_use_coeff_y[2]  );
		stat_pre.bit_use_coeff_y[0] = stat->bit_use_coeff_y[0];
		stat_pre.bit_use_coeff_y[1] = stat->bit_use_coeff_y[1];
		stat_pre.bit_use_coeff_y[2] = stat->bit_use_coeff_y[2];
	}
	else
	{
		fprintf( p_stat, " Coeffs. Y           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_y[0]-(float)stat_pre.bit_use_coeff_y[0] , ( float )stat->bit_use_coeff_y[1]-(float)stat_pre.bit_use_coeff_y[1] , 0. );
		stat_pre.bit_use_coeff_y[0] = stat->bit_use_coeff_y[0];
		stat_pre.bit_use_coeff_y[1] = stat->bit_use_coeff_y[1];
	}
	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
	{
		fprintf( p_stat, " Coeffs. C           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_c[0]-(float)stat_pre.bit_use_coeff_c[0] , ( float )stat->bit_use_coeff_c[1]-(float)stat_pre.bit_use_coeff_c[1] , ( float )stat->bit_use_coeff_c[2]-(float)stat_pre.bit_use_coeff_c[2] );
		stat_pre.bit_use_coeff_c[0] = stat->bit_use_coeff_c[0];
		stat_pre.bit_use_coeff_c[1] = stat->bit_use_coeff_c[1];
		stat_pre.bit_use_coeff_c[2] = stat->bit_use_coeff_c[2];
	}
	else
	{
		fprintf( p_stat, " Coeffs. C           | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_coeff_c[0]-(float)stat_pre.bit_use_coeff_c[0] , ( float )stat->bit_use_coeff_c[1]-(float)stat_pre.bit_use_coeff_c[1] , 0. );
		stat_pre.bit_use_coeff_c[0] = stat->bit_use_coeff_c[0];
		stat_pre.bit_use_coeff_c[1] = stat->bit_use_coeff_c[1];
		stat_pre.bit_use_coeff_c[2] = stat->bit_use_coeff_c[2];
	}
	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_delta_quant[0] , ( float )stat->bit_use_delta_quant[1] , ( float )stat->bit_use_delta_quant[2] );
	else
		fprintf( p_stat, " Delta quant         | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_delta_quant[0] , ( float )stat->bit_use_delta_quant[1] , 0. );

	if ( input->succe_b != 0 && tot_b_frm_num != 0 )
		fprintf( p_stat, " Stuffing Bits       | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_stuff_bits[0] , ( float )stat->bit_use_stuff_bits[1] , ( float )stat->bit_use_stuff_bits[2] );
	else
		fprintf( p_stat, " Stuffing Bits       | %10.2f     | %10.2f     | %10.2f     |\n", ( float )stat->bit_use_stuff_bits[0] , ( float )stat->bit_use_stuff_bits[1] , 0. );

	fprintf( p_stat, " --------------------|----------------|----------------|----------------|\n" );
	fclose( p_stat );
}
#endif
/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void encode_end()
{
    close( p_in );
    close( p_rec );
    if ( p_trace != NULL )
        fclose( p_trace );
    clear_me_module();
    clear_rdopt();
    report();
    free_glb_buf();
    free_img();
    free_qcoder();
#ifdef FastME
    if ( input->UseFME )
    {
        free_mem_FME();
    }
#endif
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
static void set_img_type()
{
    if ( input->intra_period == 0 )
    {
        if ( img->number == 0 )
        {
            img->type = I_IMG;
        }
        else
        {
            img->type = P_IMG;
            picture_coding_type = 0;
        }
    }
    else
    {
        if ( ( img->number % input->intra_period ) == 0 )
        {
            img->type = I_IMG;
        }
        else
        {
            img->type = P_IMG;
        }
    }
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int main( int argc, char **argv )
{
    int M, N, np, nb, n;
    int len = 0;
    int no_IPframes;
    if ( argc < 3 )
    {
        printf( "usage: lencod -f encoder.cfg\n" );
        exit( 0 );
    }

    configure( argc, argv );
    encode_init();

    init_QOffset();
    no_IPframes = ( input->no_frames + input->succe_b - 1 ) / ( input->succe_b + 1 ) + 1;
    stat->bit_use_header[3] = start_sequence();

    for ( img->number = 0; img->number < no_IPframes; img->number++ ) //loop though IP frames
    {
        if ( img->number != 0 && input->seqheader_period != 0 && img->number % ( input->seqheader_period * input->intra_period ) == 0 )
        {
            stat->bit_use_header[3] += terminate_sequence();
            if ( img->number != 0 && input->vec_period != 0 && img->number % ( input->vec_period * input->seqheader_period * input->intra_period ) == 0 )
            {
                len = write_video_edit_code();
                stat->bit_use_header[3] += len;
            }
            stat->bit_use_header[3] += start_sequence();

            if ( input->rc_enable )
            {
                stat_bbv_buffer( p_bbv );
                p_bbv = free_bbv_memory( p_bbv );
                p_bbv = init_bbv_memory( input );
            }
            img->seq_header_flag = 1;
        }
        img->buf_cycle = tmp_buf_cycle;
        img->frame_num = img->number % ( 1 << ( LOG2_MAX_FRAME_NUM_MINUS4 + 4 ) );
        set_img_type();

        if ( img->type == I_IMG )
        {
            img->buf_cycle = 1;
            if ( input->rc_enable )
            {
                if ( input->intra_period == 0 )
                {
                    n = input->no_frames;
                    np = no_IPframes - 1;
                    nb = input->no_frames - no_IPframes;
                }
                else
                {
                    N = input->intra_period * ( input->succe_b + 1 );
                    M = input->succe_b + 1;
                    n = ( img->number == 0 ) ? N - ( M - 1 ) : N;
                    if ( img->number / input->intra_period >= no_IPframes / input->intra_period )
                    {
                        if ( img->number != 0 )
                            n = ( no_IPframes - img->number ) + ( no_IPframes - img->number - 1 ) * input->succe_b + input->succe_b;
                        else
                            n = input->no_frames;
                    }
                    if ( img->number == 0 )
                        np = ( n + 2 * ( M - 1 ) ) / M - 1;
                    else
                        np = ( n + ( M - 1 ) ) / M - 1;
                    nb = n - np - 1;
                }
                rc_init_gop( np, nb );
            }
        }
        encode_one_frame();
#if SYNTAX_STAT
		report_one_frame();
#endif
        if ( ( input->succe_b != 0 ) && ( img->number > 0 ) )
        {
            int no_b_frames = RFM_MIN( input->succe_b, input->no_frames + input->succe_b - img->number * ( input->succe_b + 1 ) - 1 ); //consider the last Pb...bP
            img->type           = B_IMG;
            picture_coding_type = 1;
            img->buf_cycle      = tmp_buf_cycle;
            img->frame_num++;
            img->frame_num %= ( 1 << ( LOG2_MAX_FRAME_NUM_MINUS4 + 4 ) );
            for ( img->b_frame_to_code = 1; img->b_frame_to_code <= no_b_frames; img->b_frame_to_code++ )
            {
                encode_one_frame();
#if SYNTAX_STAT
				report_one_frame();
#endif
            }
        }
    }
    if ( input->rc_enable )
    {
        stat_bbv_buffer( p_bbv );
        p_bbv = free_bbv_memory( p_bbv );
    }
    img->encode_end_flag = 1;
    terminate_sequence();
    encode_end();

    return 0;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int get_mem_ACcoeff( int *****cofAC )
{
    int i, j, k;

    if ( ( *cofAC = ( int **** )calloc( 8, sizeof( int *** ) ) ) == NULL )
        no_mem_exit( "get_mem_ACcoeff: cofAC" );
    for ( k = 0; k < 8; k++ )
    {
        if ( ( ( *cofAC )[k] = ( int *** )calloc( 4, sizeof( int ** ) ) ) == NULL )
            no_mem_exit( "get_mem_ACcoeff: cofAC" );
        for ( j = 0; j < 4; j++ )
        {
            if ( ( ( *cofAC )[k][j] = ( int ** )calloc( 2, sizeof( int * ) ) ) == NULL )
                no_mem_exit( "get_mem_ACcoeff: cofAC" );
            for ( i = 0; i < 2; i++ )
            {
                if ( ( ( *cofAC )[k][j][i] = ( int * )calloc( 65, sizeof( int ) ) ) == NULL )
                    no_mem_exit( "get_mem_ACcoeff: cofAC" );
            }
        }
    }

    return 8 * 4 * 2 * 65 * sizeof( int );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
int get_mem_DCcoeff( int ****cofDC )
{
    int j, k;

    if ( ( *cofDC = ( int *** )calloc( 3, sizeof( int ** ) ) ) == NULL )
        no_mem_exit( "get_mem_DCcoeff: cofDC" );
    for ( k = 0; k < 3; k++ )
    {
        if ( ( ( *cofDC )[k] = ( int ** )calloc( 2, sizeof( int * ) ) ) == NULL )
            no_mem_exit( "get_mem_DCcoeff: cofDC" );
        for ( j = 0; j < 2; j++ )
        {
            if ( ( ( *cofDC )[k][j] = ( int * )calloc( 65, sizeof( int ) ) ) == NULL )
                no_mem_exit( "get_mem_DCcoeff: cofDC" );
        }
    }
    return 3 * 2 * 65 * sizeof( int );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void free_mem_ACcoeff( int ****cofAC )
{
    int i, j, k;

    for ( k = 0; k <  8; k++ )
    {
        for ( i = 0; i < 4; i++ )
        {
            for ( j = 0; j < 2; j++ )
            {
                free( cofAC[k][i][j] );
            }
            free( cofAC[k][i] );
        }
        free( cofAC[k] );
    }
    free( cofAC );
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/
void free_mem_DCcoeff( int ***cofDC )
{
    int i, j;

    for ( j = 0; j < 3; j++ )
    {
        for ( i = 0; i < 2; i++ )
        {
            free( cofDC[j][i] );
        }
        free( cofDC[j] );
    }
    free( cofDC );
}
